package org.opencv.ivvi.custom;

import android.graphics.Bitmap;
import android.util.Log;

import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.util.HashMap;
import java.util.Map;

import static org.opencv.ivvi.custom.BitmapHelper.createBitmap;
import static org.opencv.ivvi.custom.Constants.Standard;


/**
 * Created by duanxianping on 2017/5/17.
 */

public class AutoRecognitionHelper {

    private static AutoRecognitionHelper instance = new AutoRecognitionHelper();

    private AutoRecognitionHelper() {
    }

    public static AutoRecognitionHelper getInstance() {
        return instance;
    }

    public void init() {
        if (!OpenCVLoader.initDebug()) {
            Log.e(this.getClass().getSimpleName(), "  OpenCVLoader.initDebug(), not working.");
        } else {
            Log.d(this.getClass().getSimpleName(), "  OpenCVLoader.initDebug(), working.");
        }
    }

    /**
     * 识别图片是否3D
     *
     * @param source
     * @return
     */
    public synchronized boolean is3D(Bitmap source) {
        if (source == null) {
            return false;
        }
        double d[] = recognize(source);
        if (d[0] > Standard) {
            return true;
        }
        return false;
    }

    /**
     * 识别图片是否3D
     *
     * @param absPath
     * @return
     */
    public synchronized boolean is3D(String absPath) {
        Bitmap bitmap = BitmapHelper.compress(absPath);
        if (bitmap == null) {
            return false;
        }
        boolean is3d = is3D(bitmap);
        bitmap.recycle();
        return is3d;
    }

    public HashMap<Long, Boolean> recognize(HashMap<Long, String> data) {
        HashMap<Long, Boolean> hashMap = new HashMap<>();
        for (Map.Entry<Long, String> entry : data.entrySet()) {
            String absPath = entry.getValue();
            boolean is3d = is3D(absPath);
            hashMap.put(entry.getKey(), is3d);
        }
        return hashMap;
    }


    public void asyncRecognize(final HashMap<Long, String> data, final OnAutoRecogniztionListener callback) {
        final HashMap<Long, Boolean> hashMap = new HashMap<>();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (Map.Entry<Long, String> entry : data.entrySet()) {
                    String absPath = entry.getValue();
                    boolean is3d = is3D(absPath);
                    hashMap.put(entry.getKey(), is3d);
                }
                if (callback != null) {
                    callback.result(hashMap);
                }
            }
        }).start();

    }


    private boolean is3D(double degree) {
        if (degree > Standard) {
            return true;
        }
        return false;
    }

    public double[] recognize(Bitmap source) {
        double d[] = new double[2];
        //左右比较，目前左右图片占比高，前期先只比较左右
        d[0] = leftRight(source);
        //上下比较
//        d[1] = topBottom(source);
        return d;
    }

    private double[] recognize(String filePath) {
        double d[] = new double[2];
        //左右比较，目前左右图片占比高，前期先只比较左右
        d[0] = leftRight(filePath);
        //上下比较
//        d[1] = topBottom(filePath);
        return d;
    }


    /**
     * 左右比较
     *
     * @param source
     * @return
     */

    private double leftRight(Bitmap source) {
        Bitmap left = createBitmap(source, CropType.LEFT);
        Bitmap right = createBitmap(source, CropType.RIGHT);

        Mat leftRgbMat = new Mat();
        Mat leftGrayMat = new Mat();

        Utils.bitmapToMat(left, leftRgbMat);
        Imgproc.cvtColor(leftRgbMat, leftGrayMat, Imgproc.COLOR_RGB2GRAY);

        Mat rightRgbMat = new Mat();
        Mat rightGrayMat = new Mat();

        Utils.bitmapToMat(right, rightRgbMat);
        Imgproc.cvtColor(rightRgbMat, rightGrayMat, Imgproc.COLOR_RGB2GRAY);

        leftGrayMat.convertTo(leftGrayMat, CvType.CV_32F);
        rightGrayMat.convertTo(rightGrayMat, CvType.CV_32F);

        double d = Imgproc.compareHist(leftGrayMat, rightGrayMat, Imgproc.CV_COMP_CORREL);

        left.recycle();
        right.recycle();

        return d;

    }


    private double leftRight(String filePath) {
        double d = 0;

        Mat oriMat = Imgcodecs.imread(filePath);

        Imgproc.pyrDown(oriMat, oriMat);

        int oriWidth = oriMat.width();
        int oriHeight = oriMat.height();

        Rect left = new Rect(new Point(0, 0), new Size(oriWidth / 2, oriHeight));
        Rect right = new Rect(new Point(oriWidth / 2, 0), new Size(oriWidth / 2, oriHeight));

        Mat leftMat = oriMat.submat(left);
        Mat rightMat = oriMat.submat(right);

        Imgproc.cvtColor(leftMat, leftMat, Imgproc.COLOR_RGB2GRAY);
        Imgproc.cvtColor(rightMat, rightMat, Imgproc.COLOR_RGB2GRAY);

        leftMat.convertTo(leftMat, CvType.CV_32F);
        rightMat.convertTo(rightMat, CvType.CV_32F);

        d = Imgproc.compareHist(leftMat, rightMat, Imgproc.CV_COMP_CORREL);

        return d;

    }


    /**
     * 上下比较
     *
     * @param source
     * @return
     */

    private double topBottom(Bitmap source) {

        Bitmap top = BitmapHelper.createBitmap(source, CropType.TOP);
        Bitmap bottom = BitmapHelper.createBitmap(source, CropType.BOTTOM);

        Mat topRgbMat = new Mat();
        Mat topGrayMat = new Mat();


        Utils.bitmapToMat(top, topRgbMat);
        Imgproc.cvtColor(topRgbMat, topGrayMat, Imgproc.COLOR_RGB2GRAY);

        Mat bottomRgbMat = new Mat();
        Mat bottomGrayMat = new Mat();

        Utils.bitmapToMat(bottom, bottomRgbMat);
        Imgproc.cvtColor(bottomRgbMat, bottomGrayMat, Imgproc.COLOR_RGB2GRAY);

        topGrayMat.convertTo(topGrayMat, CvType.CV_32F);
        bottomGrayMat.convertTo(bottomGrayMat, CvType.CV_32F);

        double d = Imgproc.compareHist(topGrayMat, bottomGrayMat, Imgproc.CV_COMP_CORREL);

        top.recycle();
        bottom.recycle();
        return d;

    }


    /**
     * 上下比较
     *
     * @param filePath
     * @return
     */

    private double topBottom(String filePath) {
        double d = 0;
        Mat oriMat = Imgcodecs.imread(filePath);
        Imgproc.pyrDown(oriMat, oriMat);

        int oriWidth = oriMat.width();
        int oriHeight = oriMat.height();

        Rect top = new Rect(new Point(0, 0), new Size(oriWidth, oriHeight / 2));
        Rect bottom = new Rect(new Point(0, oriHeight / 2), new Size(oriWidth, oriHeight / 2));

        Mat topMat = oriMat.submat(top);
        Mat bottomMat = oriMat.submat(bottom);

        Imgproc.cvtColor(topMat, topMat, Imgproc.COLOR_RGB2GRAY);
        Imgproc.cvtColor(bottomMat, bottomMat, Imgproc.COLOR_RGB2GRAY);

        topMat.convertTo(topMat, CvType.CV_32F);
        bottomMat.convertTo(bottomMat, CvType.CV_32F);

        d = Imgproc.compareHist(topMat, bottomMat, Imgproc.CV_COMP_CORREL);

        return d;
    }

    public interface OnAutoRecogniztionListener {
        void result(HashMap<Long, Boolean> hashMap);
    }

}
